#include "Transport.h"
#include "deplibUV.h"
#include "rtp/Producer.h"
#include "rtp/ReceiverReport.h"
#include "rtp/RtpProbationGenerator.h"
#include "rtp/Feedback.h"
#include "rtp/FeedbackPsFir.h"
#include "rtp/FeedbackPsAfb.h"
#include "rtp/FeedbackPsRemb.h"
#include "rtp/FeedbackRtpNack.h"

#include <iostream>

void Transport::ReceiveRtpPacket(Rtp::RtpPacket *packet) {
    packet->SetMidExtensionId(this->recvRtpHeaderExtensionIds.mid);
    packet->SetRidExtensionId(this->recvRtpHeaderExtensionIds.rid);
    packet->SetRepairedRidExtensionId(this->recvRtpHeaderExtensionIds.rrid);
    packet->SetAbsSendTimeExtensionId(this->recvRtpHeaderExtensionIds.absSendTime);
    packet->SetTransportWideCc01ExtensionId(this->recvRtpHeaderExtensionIds.transportWideCc01);

    auto nowMs = DepLibUV::GetTimeMs();

    // 给到TransportCongestionControlServer的拥塞控制 

    //获取生产者
    Rtp::Producer *producer = this->rtpListener.GetProducer(packet);

    if (!producer) { // producer == nil
        std::cout << "no suitable Producer for received RTP packet" << std::endl;

        RecvStreamClosed(packet->GetSsrc());

        delete packet;

        return;
    }
    // 把packet传递给正确的producer
    auto result = producer->ReceiveRtpPacket(packet);
    switch (result)
    {
    case Rtp::Producer::ReceiveRtpPacketResult::MEDIA:
        this->recvRtpTransmission.Update(packet);
        break;
    case Rtp::Producer::ReceiveRtpPacketResult::RETRANSMISSION:
        this->recvRtxTransmission.Update(packet);
        break;
    case Rtp::Producer::ReceiveRtpPacketResult::DISCARDED:
        RecvStreamClosed(packet->GetSsrc());
        break;
    default:
        break;
    }
    delete packet;
}

void Transport::ReceiveRtcpPacket(Rtp::Rtcp::Packet *packet) {
    while (packet) {
        HandleRtcpPacket(packet);
        auto *previousPacket = packet;
        packet = packet->GetNext();
        delete previousPacket;
    }
}

void Transport::HandleRtcpPacket(Rtp::Rtcp::Packet *packet) {
    switch (packet->GetType())
    {
    case Rtp::Rtcp::Type::RR: {
        auto *rr = static_cast<Rtp::Rtcp::ReceiverReportPacket *>(packet);
        for (auto it = rr->Begin(); it != rr->End(); ++it) {
            auto& report = *it;
            // 
            auto* consumer = GetConsumerByMediaSsrc(report->GetSsrc());
            if (!consumer) {
                if (report->GetSsrc() == Rtp::RtpProbationSsrc) {
                    continue;
                }

                if (GetConsumerByRtxSsrc(report->GetSsrc()) != nullptr) {
                    continue;
                }

                continue;
            }

            consumer->ReceiveRtcpReceiverReport(report);
        }

        if (this->tccClient && !this->mapConsumers.empty()) {
            float rtt = 0;
            for (auto& kv : this->mapConsumers) {
                auto* consumer = kv.second;
                if (consumer->IsActive()) {
                    rtt = consumer->GetRtt();
                    break;
                }
            }
            this->tccClient->ReceiveRtcpReceiverReport(rr, rtt, DepLibUV::GetTimeMsInt64());
        }
    }
        break;
    case Rtp::Rtcp::Type::PSFB: {
        auto *feedback = static_cast<Rtp::Rtcp::FeedbackPsPacket *>(packet);
        switch (feedback->GetMessageType())
        {
        case Rtp::Rtcp::FeedbackPs::MessageType::PLI: {
            auto *consumer = GetConsumerByMediaSsrc(feedback->GetMediaSsrc());
            if (feedback->GetMediaSsrc() == Rtp::RtpProbationSsrc) {
                break;
            } else if (!consumer) {
                break;
            }
            consumer->ReceiveKeyFrameRequest(Rtp::Rtcp::FeedbackPs::MessageType::PLI, feedback->GetMediaSsrc());
        }
            break;
        case Rtp::Rtcp::FeedbackPs::MessageType::FIR: {
            auto* fir = static_cast<Rtp::Rtcp::FeedbackPsFirPacket*>(packet);
            for (auto it = fir->Begin(); it != fir->End(); ++it) {
                auto& item = *it;
                auto* consumer = GetConsumerByMediaSsrc(item->GetSsrc());

                if (item->GetSsrc() == Rtp::RtpProbationSsrc) {
                    continue;
                } else if (!consumer) {
                    continue;
                }
                consumer->ReceiveKeyFrameRequest(feedback->GetMessageType(), item->GetSsrc());
            }
        }
            break;
        case Rtp::Rtcp::FeedbackPs::MessageType::AFB: {
            auto *afb = static_cast<Rtp::Rtcp::FeedbackPsAfbPacket *>(feedback);
            if (afb->GetApplication() == Rtp::Rtcp::FeedbackPsAfbPacket::Application::REMB) {
                auto* remb = static_cast<Rtp::Rtcp::FeedbackPsRembPacket*>(afb);
                if (this->tccClient && this->tccClient->GetBweType() == TransportCongestionControlClient::BweType::REMB) {
                    this->tccClient->ReceiveEstimatedBitrate(remb->GetBitrate());
                }
            }
        }
            break;
        default:
            break;
        }
    }
        break;
    case Rtp::Rtcp::Type::RTPFB: {
        auto *feedback = static_cast<Rtp::Rtcp::FeedbackRtpPacket*>(packet);
        auto *consumer = GetConsumerByMediaSsrc(feedback->GetMediaSsrc());

        if (!consumer && feedback->GetMessageType() != Rtp::Rtcp::FeedbackRtp::MessageType::TCC && (
            feedback->GetMediaSsrc() != Rtp::RtpProbationSsrc || !GetConsumerByRtxSsrc(feedback->GetMediaSsrc())
        )) {
            break;
        }
        switch (feedback->GetMessageType()) {
        case Rtp::Rtcp::FeedbackRtp::MessageType::NACK: {
            if (!consumer) {
                break;
            }
            auto *nackPacket = static_cast<Rtp::Rtcp::FeedbackNack>
        }
            break;
        
        default:
            break;
        }
    }
        break;
    case Rtp::Rtcp::Type::SR:
        break;
    case Rtp::Rtcp::Type::SDES:
        break;
    case Rtp::Rtcp::Type::BYE:
        break;
    case Rtp::Rtcp::Type::XR:
        break;
    default:
        break;
    }
}